# -*- coding: utf-8 -*-
from django.db import models
from django.contrib.auth.models import Group ,User
from django.db.models.signals import post_save
from django.core.urlresolvers import reverse
from django.conf import settings
from django.utils.encoding import smart_unicode
import re, os, datetime

REPOSITORY_TYPE = (('svn', 'Subversion'),
                   ('cvs', 'Concurrent Versions System'),
                   ('local', 'Local Directory'),
                   )

DOCS_TYPE = (('sphinx', 'Sphinx'),
             ('docutils', 'Docutils'),
             )

#class EffectivePagesManager(models.Manager):
#    use_for_related_fields = True
#    def get_query_set(self):
#        return super(EffectivePagesManager, self).pages.filter(current_version=self.current_version, suspended = False)
#
class EffectiveTranslationManager(models.Manager):
    def get_query_set(self):
        return Translation.objects.filter(inherited_translations__isnull = True)

# Create your models here.
class Project(models.Model):
    name = models.CharField(max_length = 250, unique = True)
    slug = models.SlugField()
    project_description = models.TextField(blank = True)
    repository_url = models.CharField(max_length = 250)
    repository_type = models.CharField(max_length = 50, choices = REPOSITORY_TYPE, default = 'svn')
    docs_type = models.CharField(max_length = 50, choices = DOCS_TYPE, default = 'sphinx')
    exclude_dir_names = models.CharField(max_length = 250, blank = True)
    doc_file_extensions = models.CharField(max_length = 250, blank = True)
    content_order = models.CharField(max_length = 250, blank = True)
    added_version = models.IntegerField(default = 0)
    current_version = models.IntegerField(default = 0)
    created = models.DateTimeField(auto_now_add = True)
    updated = models.DateTimeField(auto_now = True)
    translators = models.ManyToManyField(User, related_name = "joined_projects", null = True, blank = True)
    suspended = models.BooleanField(default = False)
    progress_cache = models.FloatField(null = True, blank = True)
    progress_updated = models.DateTimeField(default = datetime.datetime.now)
    
    class Meta:
        verbose_name = u"project"
        verbose_name_plural = u"projects"
        
    def __unicode__(self):
        return  self.name
    
    def get_absolute_url(self):
        pass
    
    @models.permalink
    def admin_url(self):
        return ('docs.admin_views.project_page_list', [self.slug,])
    

    @models.permalink
    def join_url(self):
        return ('docs.admin_views.project_join_quit', [self.slug, 'join'])
    

    @models.permalink
    def quit_url(self):
        return ('docs.admin_views.project_join_quit', [self.slug, 'quit'])
    
    @models.permalink
    def changes_url(self):
        return ('docs.admin_views.project_versions', [self.slug,])
    
    @property
    def effective_pages(self):
        return self.pages.filter(current_version = self.current_version, suspended = False)
    
    @property
    def effective_paragraphs(self):
        return Paragraph.objects.filter(page__project = self, current_version = self.current_version)
    
    @property
    def translated_paragraphs(self):
        return self.effective_paragraphs.filter(translation__isnull = False)
    
    @property
    def progress(self):
        now = datetime.datetime.now()
        delta = now - self.progress_updated
        if delta.seconds > 3600  or self.progress_cache==None:
            self.progress_cache = float(self.translated_paragraphs.count()) * 100 / float(self.effective_paragraphs.count())
            self.progress_updated = now
            self.save()
        return self.progress_cache
    
    @property
    def docs_dir(self):
        path = os.path.join(settings.ALL_DOCS_DIR, self.slug)
        if not os.path.exists(path):
            os.makedirs(path)
        return path
    
    @property
    def original_docs_dir(self):
        return os.path.join(self.docs_dir, settings.ORIGINAL_DOCS_DIR_NAME)
    
    def is_doc_file(self, path):
        extensions = [".txt",'.rst']
        extensions.extend([n.lower() for n in self.doc_file_extensions.split()])
        exclude_dirs = []
        exclude_dirs.extend([n.lower() for n in self.exclude_dir_names.split()])
        dir_name, basename = os.path.split(path)
        bits = dir_name.split(os.path.sep)
        for bit in bits:
            if bit.startswith("_") or bit.lower() in exclude_dirs:
                return False
        filename, extension = os.path.splitext(path)
        if extension.lower() in extensions:
            return True
        return False
    
    @property
    def doc_files_set(self):
        doc_files = set()
        for root, dirs, files in os.walk(self.original_docs_dir):
            if '.svn' in dirs: dirs.remove('.svn')
            if 'CVS' in dirs: dirs.remove('CVS')
            for file in files:
                page = os.path.join(root, file).replace(self.original_docs_dir + os.sep,"")
                if self.is_doc_file(page): doc_files.add(page)
        return doc_files
    
    
class Page(models.Model):
    project = models.ForeignKey(Project, related_name = "pages")
    path = models.CharField(max_length = 250)
    slug = models.SlugField()
    added_version = models.IntegerField()
    current_version = models.IntegerField()
    created = models.DateTimeField(auto_now_add = True)
    updated = models.DateTimeField(auto_now = True)
    suspended = models.BooleanField(default = False)
    history_translators = models.ManyToManyField(User, related_name = "translatd_pages", null = True, blank = True)
    progress_cache = models.FloatField(null = True, blank = True)
    progress_updated = models.DateTimeField(default = datetime.datetime.now)
    
    class Meta:
        verbose_name = u"page"
        verbose_name_plural = u"pages"
        
    def sections(self):
        dir, base_name = os.path.split(self.path)
        sections = []
        path_bits = dir.split('/')
        for path_bit in path_bits:
            path_slug = dir[0:dir.rfind(path_bit)+len(path_bit)]
            sections.append((path_bit,path_slug))
        return sections
    
    def base_name(self):
        dir, base_name = os.path.split(self.path)
        return base_name
    
    @property
    def section_slug(self):
        if os.sep in self.path:
            return self.path.split(os.sep)[0]
        else:
            return ''
    
    @property
    def index_name(self):
        path = self.path.split('/')[1:]
        if path:
            return os.path.join(*path)
        else:
            return self.path
    
    @property
    def progress(self):
        now = datetime.datetime.now()
        delta = now - self.progress_updated
        if delta.seconds > 3600 or self.progress_cache==None:
            self.progress_cache = float(self.translated_paragraphs.count()) * 100 / float(self.effective_paragraphs.count())
            self.progress_updated = now
            self.save()
        return self.progress_cache
        
    def __unicode__(self):
        return  self.path
    
    def get_absolute_url(self):
        pass
    
    @models.permalink
    def admin_url(self):
        return ('docs.admin_views.page', [self.project.slug, self.slug])
    
    @models.permalink
    def changes_url(self):
        return ('docs.admin_views.page_change', [self.project.slug, self.slug])
    
   
    
    @property
    def effective_paragraphs(self):
        return self.paragraphs.filter(current_version = self.current_version)
    
    @property
    def translated_paragraphs(self):
        return self.effective_paragraphs.filter(translation__isnull = False)
    
    
    @property
    def is_integrity(self):
        paragraphs = self.effective_paragraphs.order_by('ordinal')
        for i, paragraph in enumerate(paragraphs):
            if i != paragraph.ordinal:
                return i
        
        f = open(os.path.join(self.project.original_docs_dir, self.path)).read().decode('utf-8')
        line_set_in_db = set(smart_unicode(l.strip().lower()) for l in "\n".join(p.original for p in paragraphs).strip().split('\n'))
        line_set_in_file = set(smart_unicode(l.strip().lower()) for l in f.strip().split('\n'))
        
        print len(line_set_in_db),len(line_set_in_file)
        return line_set_in_db ^ line_set_in_file
    
    
    def paragraphs_link(self):
        paragraphs = self.effective_paragraphs.select_related().order_by('ordinal')
        links = []
        for p in paragraphs:
            if p.translation:
                links.append('<a href="%s#translation%s"><big>%s</big></a>' % (self.admin_url(), p.id, p.ordinal))
            else:
                links.append('<a href="%s#%s">%s</a>' % (self.admin_url(), p.ordinal, p.ordinal))
        return " ".join(links)
    paragraphs_link.allow_tags = True
    
    def changes_link(self):
        changes = self.changes.select_related().order_by('created')
        return " ".join(('<a href="%s">%s</a>'% (c.admin_url(), c.version.revision) for c in changes))
    changes_link.allow_tags = True
    
    
class Paragraph(models.Model):
    page = models.ForeignKey(Page, related_name = "paragraphs")
    added_version = models.IntegerField()
    current_version = models.IntegerField()
    created = models.DateTimeField(auto_now_add = True)
    updated = models.DateTimeField(auto_now = True)
    title = models.CharField(max_length = 250)
    slug = models.SlugField()
    original = models.TextField()
    ordinal = models.IntegerField()
    history = models.ForeignKey('self', related_name = "modified_paragraphs", null = True, blank = True)
    translation = models.ForeignKey("Translation", related_name = "applied_paragraphs", null = True, blank = True)
    review = models.BooleanField(default = False)
    reviewed_by = models.ForeignKey(User, null = True, blank = True)
    reviewed_at = models.DateTimeField(null = True, blank = True)
    
    class Meta:
        verbose_name = u"paragraph"
        verbose_name_plural = u"paragraphs"
        
    @classmethod
    def effective_paragraphs(cls):
        return cls.objects.filter(current_version = Version.latest_version().revision)
    
    def histories(self):
        histories_list = [(self, self.translations.order_by('id')),]
        paragraph = self
        while paragraph.history:
            history = paragraph.history
            histories_list.insert(0,(history, history.translations.order_by('id')))
            paragraph = history
        paragraph = self
        while paragraph.modified_paragraphs.count():
            modified = paragraph.modified_paragraphs.all()[0]
            histories_list.append((modified, modified.translations.order_by('id')))
            paragraph = modified
        
        return histories_list
    
    def __unicode__(self):
        return  self.title[:35]
        

    def get_absolute_url(self):
        pass
    
    def trans_content(self):
        if self.translation:
            return self.translation.content
        else:
            return self.original
    
    def admin_url(self):
        return "%s#%s" % (self.page.admin_url(), self.ordinal)
    
    
    def admin_changes_url(self):
        return "%s#%s" % (reverse('docs.admin_views.paragraph_history', args = [self.id, ]), self.current_version)
    
    
    def history_link(self):
        if self.history:
            return '<a href="%s">history</a>'% self.admin_changes_url()
        else:
            return "no history"
        
    history_link.allow_tags = True
    
    def translation_link(self):
        if self.translation:
            return '<a href="%s">%s</a>'% (self.translation.admin_url(), self.translation)
        else:
            return "no translation"
    translation_link.allow_tags = True
    
class Translation(models.Model):
    paragraph = models.ForeignKey(Paragraph, related_name = "translations")
    inherited_from = models.ForeignKey('self', related_name = "inherited_translations", null = True, blank = True)
    translator = models.ForeignKey(User, related_name = "translations", null = True, blank = True)
    content = models.TextField()
    created = models.DateTimeField(auto_now_add = True)
    ip = models.IPAddressField()
    location = models.CharField(max_length = 50, blank = True)
    
    objects = models.Manager()
    effectives = EffectiveTranslationManager()
    
    class Meta:
        verbose_name = u"translation"
        verbose_name_plural = u"translations"
        get_latest_by = 'created'
        
    
    def histories(self):
        histories_list = [(self, True),]
        t = self
        while t.inherited_from:
            inherited_from = t.inherited_from
            histories_list.insert(0,(inherited_from, False))
            t = inherited_from
        t = self
        while t.inherited_translations.count():
            inherited = t.inherited_translations.all()[0]
            histories_list.append((inherited, False))
            t = inherited
        
        return histories_list
    
    
    def admin_url(self):
        return "%s#translation%s" % (self.paragraph.page.admin_url(), self.paragraph.id)
    
    def admin_changes_url(self):
        return "%s#%s" % (reverse('docs.admin_views.paragraph_history', args = [self.paragraph.id, ]), self.id)
    
    def history_links(self):
        histories = self.histories()
        links = []
        for h, is_self in histories:
            if is_self:
                links.append('<a href="%s"><big>%s</big></a>' % (h.admin_changes_url(), h.id))
            else:
                links.append('<a href="%s">%s</a>' %  (h.admin_changes_url(), h.id))
                
        return " ".join(links)
    history_links.allow_tags = True
    
    def __unicode__(self):
        return  self.content.split('\n')[0]

def translation_post_save(sender, instance, created, **kwargs):
    if created:
        paragraph = instance.paragraph
        paragraph.translation = instance
        paragraph.save()
        paragraph.page.history_translators.add(instance.translator)

post_save.connect(translation_post_save, sender = Translation)

class Version(models.Model):
    project = models.ForeignKey(Project, related_name = "versions")
    last_version = models.ForeignKey('self', related_name = "next_versions", null = True, blank = True)
    revision = models.IntegerField()
    created = models.DateTimeField(auto_now_add = True)
    log = models.TextField(blank = True)
    changed = models.BooleanField()
    
    class Meta:
        verbose_name = u"version"
        verbose_name_plural = u"versions"
        get_latest_by = 'created'
    
        
    def page_changes_link(self):
        page_changes = self.changes.select_related().order_by('page')
        return "<br />".join(('<a href="%s">%s</a>'% (p.admin_url(), p.page.path) for p in page_changes))
    page_changes_link.allow_tags = True
    

    def admin_url(self):
        return "%s#%s" % (self.project.changes_url, self.revision)

    @classmethod
    def latest_version(cls):
        return cls.objects.latest()
    
    
    def __unicode__(self):
        return  u"%s (%s)" % (self.project, self.revision)
    
class PageChange(models.Model):
    page = models.ForeignKey(Page, related_name = "changes")
    version = models.ForeignKey(Version, related_name = "changes")
    paragraphs = models.ManyToManyField(Paragraph, related_name = "changes", null = True, blank = True)
    created = models.DateTimeField(auto_now_add = True)
    
    class Meta:
        verbose_name = u"page change"
        verbose_name_plural = u"page changes"
        
    def __unicode__(self):
        return  u"page %s change at version %s" % (self.page, self.version)
    
    def get_absolute_url(self):
        pass
    
    def is_change(self):
        if self.is_added() or self.is_deleted():
            return False
        return True
    
    def is_added(self):
        return self.page.added_version == self.version.revision
    
    def is_deleted(self):
        return self.page.suspended and self.page.current_version == self.version.revision
    
    def admin_url(self):
        return "%s#%s" % (self.page.admin_changes_url(), self.version.revision)
    
    
    def paragraphs_link(self):
        paragraphs = self.paragraphs.order_by('page', 'ordinal')
        if paragraphs:
            p_links = []
            for p in paragraphs:
                p_link = '<a href="%s">%s</a> #%s <a href="%s"> %s </a> ' % (self.admin_url(),
                                                                          p.page,
                                                                          p.ordinal,
                                                                          p.admin_changes_url(),
                                                                          p.title,)
                if p.history:
                    p_link += ' history: <a href="%s"> %s </a>' % (p.history.admin_changes_url(),
                                                                p.history.title,)
                p_links.append(p_link)
            return "<br />".join(p_links)
        else:
            if self.is_deleted():
                return "deleted"
            elif self.is_added():
                return "added"
        return ""
    paragraphs_link.allow_tags = True
    

#
#class Comment(models.Model):
#    page = models.ForeignKey(Page, related_name = "comments")
#    paragraph = models.ForeignKey(Paragraph, related_name = "comments", null = True, blank = True)
#    translation = models.ForeignKey(Translation, related_name = "comments", null = True, blank = True)
#    user = models.ForeignKey(User, related_name = "comments", null = True, blank = True)
#    name = models.CharField(max_length = 50)
#    email = models.EmailField()
#    content = models.TextField()
#    created = models.DateTimeField(auto_now_add = True)
#    ip = models.IPAddressField()
#    location = models.CharField(max_length = 50, blank = True)
#    
#    def __unicode__(self):
#        return  self.content[:30]
